<script setup lang="ts">
import type { ISysDept } from '@/api/interface/system/admin/dept'
import { computed, nextTick, onMounted, ref, watch } from 'vue'
import { getMenuTree } from '@/api/modules/system/admin/dept'
import DeptTreeNode from './DeptTreeNode.vue'

defineOptions({
  name: 'DeptSelect',
})

const props = withDefaults(defineProps<Props>(), {
  multiple: false,
  placeholder: '请选择部门',
  clearable: true,
  disabled: false,
  checkStrictly: true,
  filterable: true,
  excludeNodeId: undefined,
  filterSystemDepts: true,
  maxDisplayTags: 2,
})

const emit = defineEmits<{
  'update:modelValue': [value: number | number[] | null]
  change: [value: number | number[] | null, data?: ISysDept.Tree | ISysDept.Tree[]]
}>()

interface Props {
  modelValue?: number | number[] | null
  multiple?: boolean
  placeholder?: string
  clearable?: boolean
  disabled?: boolean
  checkStrictly?: boolean
  filterable?: boolean
  excludeNodeId?: number
  filterSystemDepts?: boolean
  maxDisplayTags?: number
}

// 组件引用
const deptPopup = ref()

// 响应式数据
const loading = ref(false)
const deptTree = ref<ISysDept.Tree[]>([])
const tempSelectedIds = ref<number[]>([])
const searchKeyword = ref('')
const expandedNodes = ref<Set<number>>(new Set())
const showDeptPicker = ref(false)

// 计算属性
const hasValue = computed(() => {
  if (props.multiple) {
    return Array.isArray(props.modelValue) && props.modelValue.length > 0
  }
  return props.modelValue !== null && props.modelValue !== undefined
})

const selectedDeptData = computed(() => {
  if (!props.multiple && typeof props.modelValue === 'number') {
    return findNodeById(deptTree.value, props.modelValue)
  }
  return null
})

const selectedDeptsData = computed(() => {
  if (props.multiple && Array.isArray(props.modelValue)) {
    return props.modelValue
      .map((id) => findNodeById(deptTree.value, id))
      .filter(Boolean) as ISysDept.Tree[]
  }
  return []
})

const displaySelectedDepts = computed(() => {
  return selectedDeptsData.value.slice(0, props.maxDisplayTags)
})

const filteredDeptTree = computed(() => {
  if (!searchKeyword.value) {
    return deptTree.value
  }
  return filterTreeByKeyword(deptTree.value, searchKeyword.value)
})

const deptSelectorText = computed(() => {
  const count = props.multiple ? selectedDeptsData.value.length : selectedDeptData.value ? 1 : 0
  if (count === 0) return props.placeholder
  if (props.multiple) {
    return count === 1 ? selectedDeptsData.value[0].name : `已选 ${count} 个部门`
  }
  return selectedDeptData.value?.name || props.placeholder
})

// 工具函数
function findNodeById(tree: ISysDept.Tree[], id: number): ISysDept.Tree | null {
  for (const node of tree) {
    if (node.id === id) return node
    if (node.children && node.children.length > 0) {
      const found = findNodeById(node.children, id)
      if (found) return found
    }
  }
  return null
}

function filterTreeByKeyword(tree: ISysDept.Tree[], keyword: string): ISysDept.Tree[] {
  const result: ISysDept.Tree[] = []

  for (const node of tree) {
    if (node.name.includes(keyword)) {
      result.push({ ...node })
    } else if (node.children && node.children.length > 0) {
      const filteredChildren = filterTreeByKeyword(node.children, keyword)
      if (filteredChildren.length > 0) {
        result.push({
          ...node,
          children: filteredChildren,
        })
      }
    }
  }

  return result
}

function getAllChildIds(node: ISysDept.Tree): number[] {
  const ids: number[] = [node.id]
  if (node.children && node.children.length > 0) {
    for (const child of node.children) {
      ids.push(...getAllChildIds(child))
    }
  }
  return ids
}

// 事件处理
function openDeptPicker() {
  if (props.disabled) return

  // 初始化临时选中状态
  if (props.multiple) {
    tempSelectedIds.value = Array.isArray(props.modelValue) ? [...props.modelValue] : []
  } else {
    tempSelectedIds.value = typeof props.modelValue === 'number' ? [props.modelValue] : []
  }

  showDeptPicker.value = true
}

function closeDeptPicker() {
  showDeptPicker.value = false
  searchKeyword.value = ''
}

function confirmSelection() {
  let finalValue: number | number[] | null

  if (props.multiple) {
    finalValue = tempSelectedIds.value.length > 0 ? tempSelectedIds.value : []
  } else {
    finalValue = tempSelectedIds.value.length > 0 ? tempSelectedIds.value[0] : null
  }

  emit('update:modelValue', finalValue)

  // 触发change事件
  let selectedData: ISysDept.Tree | ISysDept.Tree[] | undefined
  if (props.multiple) {
    selectedData = tempSelectedIds.value
      .map((id) => findNodeById(deptTree.value, id))
      .filter(Boolean) as ISysDept.Tree[]
  } else if (tempSelectedIds.value.length > 0) {
    selectedData = findNodeById(deptTree.value, tempSelectedIds.value[0]) || undefined
  }

  emit('change', finalValue, selectedData)

  closeDeptPicker()
}

function handleNodeSelect(node: ISysDept.Tree, selected: boolean) {
  if (props.multiple) {
    if (selected) {
      if (!tempSelectedIds.value.includes(node.id)) {
        tempSelectedIds.value.push(node.id)

        // 如果不是严格模式，选中父节点时同时选中所有子节点
        if (!props.checkStrictly) {
          const childIds = getAllChildIds(node).slice(1) // 排除自身
          childIds.forEach((id) => {
            if (!tempSelectedIds.value.includes(id)) {
              tempSelectedIds.value.push(id)
            }
          })
        }
      }
    } else {
      const index = tempSelectedIds.value.indexOf(node.id)
      if (index > -1) {
        tempSelectedIds.value.splice(index, 1)

        // 如果不是严格模式，取消选中父节点时同时取消选中所有子节点
        if (!props.checkStrictly) {
          const childIds = getAllChildIds(node).slice(1)
          childIds.forEach((id) => {
            const childIndex = tempSelectedIds.value.indexOf(id)
            if (childIndex > -1) {
              tempSelectedIds.value.splice(childIndex, 1)
            }
          })
        }
      }
    }
  } else {
    // 单选模式
    tempSelectedIds.value = selected ? [node.id] : []
    if (!props.multiple && selected) {
      confirmSelection()
    }
  }
}

function handleNodeToggle(nodeId: number, expanded: boolean) {
  if (expanded) {
    expandedNodes.value.add(nodeId)
  } else {
    expandedNodes.value.delete(nodeId)
  }
}

function removeDept(deptId: number) {
  if (props.disabled) return

  let newValue: number | number[] | null

  if (props.multiple && Array.isArray(props.modelValue)) {
    const newIds = props.modelValue.filter((id) => id !== deptId)
    newValue = newIds.length > 0 ? newIds : []
  } else {
    newValue = null
  }

  emit('update:modelValue', newValue)

  // 触发change事件
  let selectedData: ISysDept.Tree | ISysDept.Tree[] | undefined
  if (props.multiple && Array.isArray(newValue)) {
    selectedData = newValue
      .map((id) => findNodeById(deptTree.value, id))
      .filter(Boolean) as ISysDept.Tree[]
  }

  emit('change', newValue, selectedData)
}

function clearSelection() {
  if (props.disabled) return

  const newValue = props.multiple ? [] : null
  emit('update:modelValue', newValue)
  emit('change', newValue, undefined)
}

function handleSearch() {
  // 搜索时自动展开所有节点
  if (searchKeyword.value) {
    const getAllNodeIds = (tree: ISysDept.Tree[]): number[] => {
      const ids: number[] = []
      for (const node of tree) {
        ids.push(node.id)
        if (node.children && node.children.length > 0) {
          ids.push(...getAllNodeIds(node.children))
        }
      }
      return ids
    }

    const allIds = getAllNodeIds(deptTree.value)
    expandedNodes.value = new Set(allIds)
  }
}

function clearSearch() {
  searchKeyword.value = ''
  expandedNodes.value.clear()
}

// 加载部门树数据
async function loadDeptTree() {
  if (loading.value) return

  loading.value = true
  try {
    const params: any = {}
    if (props.excludeNodeId !== undefined) {
      params.excludeNodeId = props.excludeNodeId
    }

    const response = await getMenuTree(params)
    deptTree.value = response.data || []
  } catch (error) {
    console.error('加载部门树失败:', error)
    deptTree.value = []
    uni.showToast({
      title: '加载部门数据失败',
      icon: 'none',
    })
  } finally {
    loading.value = false
  }
}

// 监听excludeNodeId变化
watch(
  () => props.excludeNodeId,
  () => {
    loadDeptTree()
  },
  { immediate: false },
)

// 组件挂载时加载数据
onMounted(() => {
  loadDeptTree()
})

// 暴露方法
defineExpose({
  loadDeptTree,
  deptTree: computed(() => deptTree.value),
})
</script>

<template>
  <view class="dept-select-container">
    <!-- 主选择器 -->
    <view class="main-selector">
      <view
        class="dept-trigger"
        :class="{ 'dept-trigger--active': showDeptPicker, 'dept-trigger--disabled': disabled }"
        @click="!disabled && openDeptPicker()"
      >
        <view class="trigger-content">
          <wd-icon name="home" class="trigger-icon" />
          <text class="trigger-text" :class="{ 'trigger-text--placeholder': !hasValue }">
            {{ deptSelectorText }}
          </text>
        </view>
        <view class="trigger-actions">
          <wd-icon
            v-if="clearable && hasValue && !disabled"
            name="close"
            size="16"
            class="trigger-clear"
            @click.stop="clearSelection"
          />
          <wd-icon
            name="arrow-down"
            size="16"
            class="trigger-arrow"
            :class="{ 'trigger-arrow--active': showDeptPicker }"
          />
        </view>
      </view>
    </view>

    <!-- 已选部门标签显示 (多选模式) -->
    <view v-if="props.multiple && selectedDeptsData.length > 0" class="selected-depts-tags">
      <view
        v-for="dept in displaySelectedDepts"
        :key="dept.id"
        class="dept-tag"
        @click.stop="removeDept(dept.id)"
      >
        <wd-icon name="home" size="12" class="tag-icon" />
        <text class="tag-text">
          {{ dept.name }}
        </text>
        <view class="tag-close">
          <wd-icon name="close" size="12" />
        </view>
      </view>
      <view v-if="selectedDeptsData.length > maxDisplayTags" class="more-tag">
        +{{ selectedDeptsData.length - maxDisplayTags }}
      </view>
    </view>

    <!-- 部门选择弹窗 -->
    <wd-popup
      v-model="showDeptPicker"
      position="bottom"
      :close-on-click-modal="true"
      class="dept-picker-popup"
      :safe-area-inset-bottom="true"
    >
      <view class="picker-container">
        <!-- 头部 -->
        <view class="picker-header">
          <view class="picker-header-content">
            <view class="picker-header-left">
              <wd-button type="text" size="small" class="picker-close-btn" @click="closeDeptPicker">
                <wd-icon name="close" size="20" />
              </wd-button>
            </view>
            <text class="picker-title">选择部门</text>
            <view class="picker-header-right">
              <wd-button
                type="primary"
                size="small"
                class="picker-done-btn"
                @click="confirmSelection"
              >
                完成
              </wd-button>
            </view>
          </view>
        </view>

        <!-- 搜索框 -->
        <view v-if="filterable" class="picker-search">
          <view class="search-input-wrapper">
            <wd-icon name="search" size="16" class="search-icon" />
            <input
              v-model="searchKeyword"
              placeholder="搜索部门"
              class="search-input"
              @input="handleSearch"
            />
            <wd-icon
              v-if="searchKeyword"
              name="close"
              size="16"
              class="search-clear"
              @click="clearSearch"
            />
          </view>
        </view>

        <!-- 部门树 -->
        <scroll-view class="picker-content" scroll-y :enhanced="true" :show-scrollbar="false">
          <view class="dept-tree">
            <template v-if="filteredDeptTree.length > 0">
              <DeptTreeNode
                v-for="dept in filteredDeptTree"
                :key="dept.id"
                :node="dept"
                :level="0"
                :selected-ids="tempSelectedIds"
                :multiple="multiple"
                :check-strictly="checkStrictly"
                :expanded-nodes="expandedNodes"
                @select="handleNodeSelect"
                @toggle="handleNodeToggle"
              />
            </template>
            <view v-else-if="loading" class="loading-container">
              <wd-loading size="16px" />
              <text class="loading-text">加载中...</text>
            </view>
            <view v-else class="empty-container">
              <text class="empty-text">暂无部门数据</text>
            </view>
          </view>
        </scroll-view>
      </view>
    </wd-popup>
  </view>
</template>

<style lang="scss" scoped>
// Apple 设计系统变量
:root {
  --apple-blue: #007aff;
  --apple-blue-light: #5ac8fa;
  --apple-blue-dark: #0056cc;
  --apple-gray: #8e8e93;
  --apple-gray-light: #c7c7cc;
  --apple-gray-dark: #48484a;
  --apple-red: #ff3b30;
  --apple-green: #34c759;
  --apple-background: #f2f2f7;
  --apple-surface: #ffffff;
  --apple-radius: 12px;
  --apple-radius-small: 8px;
  --apple-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  --apple-shadow-elevated: 0 4px 20px rgba(0, 0, 0, 0.15);
}

.dept-select-container {
  width: 100%;
  font-family:
    -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;

  // 主选择器样式
  .main-selector {
    .dept-trigger {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 16px 20px;
      background-color: var(--apple-surface);
      border: 1px solid rgba(0, 0, 0, 0.08);
      border-radius: 12px;
      min-height: 52px;
      box-sizing: border-box;
      cursor: pointer;
      transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
      user-select: none;
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);

      .trigger-content {
        display: flex;
        align-items: center;
        flex: 1;
        gap: 10px;
      }

      .trigger-icon {
        color: var(--apple-blue);
        font-size: 20px;
      }

      .trigger-text {
        font-size: 16px;
        color: #1d1d1f;
        line-height: 1.4;
        font-weight: 500;

        &--placeholder {
          color: var(--apple-gray);
          font-weight: 400;
        }
      }

      .trigger-actions {
        display: flex;
        align-items: center;
        gap: 8px;
      }

      .trigger-clear {
        color: var(--apple-gray);
        transition: all 0.2s ease;
        cursor: pointer;
        padding: 4px;
        border-radius: 50%;

        &:hover {
          color: var(--apple-gray-dark);
          background-color: rgba(0, 0, 0, 0.05);
        }

        &:active {
          transform: scale(0.9);
        }
      }

      .trigger-arrow {
        color: var(--apple-gray);
        transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);

        &--active {
          transform: rotate(180deg);
          color: var(--apple-blue);
        }
      }

      &:active {
        transform: scale(0.98);
        box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
      }

      &--active {
        border-color: var(--apple-blue);
        box-shadow: 0 4px 20px rgba(0, 122, 255, 0.15);
      }

      &--disabled {
        opacity: 0.6;
        pointer-events: none;
        background-color: rgba(142, 142, 147, 0.12);
      }
    }
  }

  // 已选部门标签
  .selected-depts-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 12px;

    .dept-tag {
      display: flex;
      align-items: center;
      gap: 6px;
      padding: 8px 12px;
      background-color: rgba(0, 122, 255, 0.08);
      border: 1px solid rgba(0, 122, 255, 0.2);
      border-radius: 16px;
      transition: all 0.2s ease;

      &:active {
        transform: scale(0.95);
        background-color: rgba(0, 122, 255, 0.12);
      }

      .tag-icon {
        color: var(--apple-blue);
      }

      .tag-text {
        font-size: 14px;
        color: var(--apple-blue);
        font-weight: 500;
        max-width: 120px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }

      .tag-close {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 18px;
        height: 18px;
        border-radius: 50%;
        background-color: rgba(0, 0, 0, 0.1);
        margin-left: 4px;
        color: var(--apple-gray);
        transition: all 0.2s ease;

        &:active {
          background-color: rgba(255, 59, 48, 0.2);
          color: var(--apple-red);
          transform: scale(0.9);
        }
      }
    }

    .more-tag {
      padding: 6px 12px;
      background-color: rgba(142, 142, 147, 0.12);
      border-radius: 16px;
      font-size: 14px;
      color: var(--apple-gray);
      font-weight: 500;
    }
  }
}

// 弹窗样式
.dept-picker-popup {
  .picker-container {
    background-color: var(--apple-surface);
    border-radius: 16px 16px 0 0;
    overflow: hidden;
    box-shadow: 0 -2px 20px rgba(0, 0, 0, 0.1);
    max-height: 85vh;
    padding-bottom: 50px; // 底部安全空间
  }

  .picker-header {
    background-color: var(--apple-surface);
    border-bottom: 0.5px solid var(--apple-gray-light);

    .picker-header-content {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 16px 20px;
      position: relative;
    }

    .picker-header-left {
      width: 44px;
      height: 44px;
      display: flex;
      align-items: center;
      justify-content: flex-start;
    }

    .picker-header-right {
      width: 44px;
      height: 44px;
      display: flex;
      align-items: center;
      justify-content: flex-end;
    }

    .picker-close-btn {
      width: 36px;
      height: 36px;
      border-radius: 18px;
      background-color: rgba(142, 142, 147, 0.12);
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 0;
      margin: 0;
      border: none;
      transition: all 0.2s ease;

      &:active {
        background-color: rgba(142, 142, 147, 0.2);
        transform: scale(0.95);
      }

      wd-icon {
        color: var(--apple-gray-dark);
      }
    }

    .picker-title {
      position: absolute;
      left: 50%;
      transform: translateX(-50%);
      font-size: 17px;
      font-weight: 600;
      color: #1d1d1f;
      line-height: 1.4;
    }

    .picker-done-btn {
      background-color: var(--apple-blue);
      border-radius: 16px;
      padding: 8px 16px;
      font-weight: 600;
      border: none;
      color: white;
      font-size: 15px;
      line-height: 1.2;
      transition: all 0.2s ease;

      &:active {
        background-color: var(--apple-blue-dark);
        transform: scale(0.95);
      }
    }
  }

  .picker-search {
    padding: 16px 20px;
    background-color: var(--apple-surface);
    border-bottom: 0.5px solid var(--apple-gray-light);

    .search-input-wrapper {
      position: relative;
      display: flex;
      align-items: center;
      background-color: rgba(142, 142, 147, 0.12);
      border-radius: 10px;
      border: none;
      padding: 10px 12px;
      transition: all 0.2s ease;

      &:focus-within {
        background-color: rgba(142, 142, 147, 0.16);
        transform: scale(1.02);
      }

      .search-icon {
        color: var(--apple-gray);
        margin-right: 8px;
      }

      .search-input {
        flex: 1;
        border: none;
        outline: none;
        font-size: 16px;
        color: #1d1d1f;
        background: transparent;
        font-weight: 400;

        &::placeholder {
          color: var(--apple-gray);
        }
      }

      .search-clear {
        color: var(--apple-gray);
        cursor: pointer;
        padding: 4px;
        margin-left: 8px;
        transition: all 0.2s ease;
        border-radius: 50%;

        &:active {
          background-color: rgba(142, 142, 147, 0.2);
          transform: scale(0.9);
        }
      }
    }
  }

  .picker-content {
    max-height: 50vh;
    padding: 16px 20px;
    background-color: var(--apple-surface);

    .dept-tree {
      min-height: 200px;
    }

    .loading-container,
    .empty-container {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      padding: 40px 20px;
      gap: 12px;
    }

    .loading-text,
    .empty-text {
      font-size: 15px;
      color: var(--apple-gray);
      font-weight: 500;
    }
  }
}

// 深色模式适配
@media (prefers-color-scheme: dark) {
  :root {
    --apple-background: #000000;
    --apple-surface: #1c1c1e;
    --apple-gray: #8e8e93;
    --apple-gray-light: #48484a;
    --apple-gray-dark: #ebebf5;
    --apple-blue: #0a84ff;
    --apple-blue-light: #64d2ff;
    --apple-blue-dark: #0040dd;
  }
}

// 响应式断点
@media (max-width: 375px) {
  .dept-select-container {
    .dept-trigger {
      padding: 12px 14px;
    }
  }
}
</style>
